package hamaster.jpbc.mgr;

import hamaster.jpbc.IDKey;
import hamaster.jpbc.User;
import hamaster.jpbc.dao.EmailsDAO;
import hamaster.jpbc.dao.IDKeyDAO;
import hamaster.jpbc.dao.UserDAO;
import hamaster.jpbc.pbc.PBC;
import hamaster.jpbc.pbc.PrivateKey;
import hamaster.jpbc.pbc.io.BinaryIDIOImpl;
import hamaster.jpbc.pbc.io.ID;
import hamaster.jpbc.pbc.io.IDIO;
import hamaster.jpbc.pbs.PBS;
import hamaster.jpbc.pbs.PersonalParameter;
import hamaster.jpbc.sys.IBCSystem;
import it.unisa.dia.gas.jpbc.Element;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.json.JSONObject;

public class IDKeyManager implements ManagerConstraint {

	protected IDKeyDAO dao;

	protected UserDAO userDAO;

	protected EmailsDAO emailsDAO;

	public IDKeyManager() {
	}

	public void idKeyDetails(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String id0 = request.getParameter("id");
		Integer id;
		try {
			id = Integer.parseInt(id0);
		} catch (NumberFormatException e) {
			return;
		}
		response.setContentType("application/json;charset=UTF-8");
		response.setCharacterEncoding("UTF-8");
		PrintWriter out = response.getWriter();
		IDKey key = dao.get(IDKey.class, id);
		if (key == null) {
			Properties resp = new Properties();
			resp.setProperty(errcode, String.valueOf(ID_KEY_NOT_FOUND));
			//未找到身份文件
			resp.setProperty(errmsg, "\u672a\u627e\u5230\u8eab\u4efd\u6587\u4ef6");
			JSONObject jo = new JSONObject(resp);
			out.println(jo.toString());
			out.flush();
			out.close();
			return;
		}
		User o = (User) request.getSession().getAttribute("user");
		if (!key.getOwner().equals(o)) {
			return;
		}
		IDIO io = new BinaryIDIOImpl(key.getKeyContent());
		ID userID = io.load();
		String hUser = userID.getPersonalParameter().getrIDString();
		Date gDate = key.getGenDate();
		User owner = key.getOwner();

		Properties keyDetail = new Properties();
		keyDetail.setProperty(errcode, String.valueOf(NO_ERROR));
		keyDetail.setProperty(genDate, String.valueOf(gDate.getTime()));
		keyDetail.setProperty(applicant, owner.getUsername());
		if (hUser.contains("#")) {
			String[] tt = hUser.split("#");
			keyDetail.setProperty(ManagerConstraint.owner, tt[0]);
			keyDetail.setProperty(timeStamp, tt[1]);
			keyDetail.setProperty(hasTimeStamp, "true");
		} else {
			keyDetail.setProperty(ManagerConstraint.owner, hUser);
			keyDetail.setProperty(hasTimeStamp, "false");
		}
		JSONObject jo = new JSONObject(keyDetail);
		out.println(jo.toString());
		out.flush();
		out.close();
		userID = null;
	}

	public void apply(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		User owner = (User) session.getAttribute("user");
		IDKey key = dao.get(owner);
		if (key != null) {
			response.sendRedirect("ibcid.jsp?reason=1");
			return;
		}
		String email = request.getParameter("email");
		if (!IBCSystem.checkEmail(email)) {
			response.sendRedirect("ibcid.jsp?reason=2");
			return;
		}
		if (!emailsDAO.checkEmailBinding(owner, email)) {
			// Email 不属于 owner
			response.sendRedirect("ibcid.jsp?reason=3");
			return;
		}
		String password = request.getParameter("password");
		String hash = IBCSystem.hash(password + new SimpleDateFormat("yyMMddHHmmss").format(owner.getRegDate()));
		if (!hash.equalsIgnoreCase(owner.getPassword())) {
			response.sendRedirect("ibcid.jsp?reason=4");
			return;
		}
		// TODO 检查是否附加了时间请求
		String idStr = email;

		ID id = new ID();
		id.setPublicParameter(IBCSystem.publicParameter());
		PBC pbc = PBC.instance();
		PBS pbs = PBS.instance(pbc);
		Element alpha = pbc.getPairing().getZr().newElement();
		PersonalParameter perp = pbs.genernate(alpha, idStr);
		Element rID = pbc.getPairing().getZr().newRandomElement();
		PrivateKey prik = pbc.keygen(perp.getUser(), rID, IBCSystem.systemKey(), IBCSystem.publicParameter());
		id.setPersonalParameter(perp);
		id.setPrivateKey(prik);
		id.setSignatureKey(alpha);
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		IDIO idio = new BinaryIDIOImpl(out);
		idio.save(id);

		// TODO 加密密钥
		byte[] rawKey = out.toByteArray();

		IDKey idKey = new IDKey();
		idKey.setGenDate(new Date());
		idKey.setOwner(owner);
		idKey.setKeyContent(rawKey);
		try {
			dao.add(idKey);
			response.sendRedirect("ibcid.jsp");
		} catch (Exception e) {
			e.printStackTrace();
			response.sendError(500);
		}
	}

	public void setDao(IDKeyDAO dao) {
		this.dao = dao;
	}

	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}

	public void setEmailsDAO(EmailsDAO emailsDAO) {
		this.emailsDAO = emailsDAO;
	}

	public EmailsDAO getEmailsDAO() {
		return emailsDAO;
	}
}
